//
// Created by jerry on 2021/3/31.
//
#include <jni.h>
#include <string.h>
#include <sys/system_properties.h>
#include <android/log.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

/* 生成字符串 */
char* getString(int length) {
    int flag, i;
    char *string;
    srand((unsigned) time(NULL));
    if ((string = (char *) malloc(length)) == NULL) {
        return NULL;
    }

    for (i = 0; i < length - 1; i++) {
        flag = rand() % 3;
        switch (flag) {
            case 0:
                string[i] = 'A' + rand() % 26;
                break;
            case 1:
                string[i] = 'a' + rand() % 26;
                break;
            case 2:
                string[i] = '0' + rand() % 10;
                break;
            default:
                string[i] = 'x';
                break;
        }
    }
    string[length - 1] = '\0';
    return string;
}


// #define JNIREG_CLASS "com.example.jnitestdemo.JNITest" // 指定要注册的类 Android 5.0之前用这种方式(.)隔开
#define JNIREG_CLASS "com/example/jnitestdemo/JNITest"    // 指定要注册的类 Android 5.0之后用这种方式(/)隔开

void c_to_java_test(JNIEnv * env)
{
    srand(time(0));
    int type = rand() % 1000;

    jclass jClass = (*env)->FindClass(env, JNIREG_CLASS);
    if (jClass == 0) {
        return;
    }

    jobject jObject = (*env)->AllocObject(env,jClass);
    if (jObject == NULL) {
        return;
    }

    jmethodID jMethodId = (*env)->GetMethodID(env,jClass,"CtoJavaReturn", "(I)I");
    if (jMethodId == NULL) {
        return;
    }

    (**env).CallIntMethod(env,jObject,jMethodId,type);
}

JNIEXPORT jstring JNICALL jni_call_java_to_c(JNIEnv *env, jclass clazz)
{
    return (*env)->NewStringUTF(env, getString(5));
}

JNIEXPORT jstring JNICALL jni_call_c_to_java(JNIEnv *env, jclass clazz)
{
    c_to_java_test(env);
    return (*env)->NewStringUTF(env, "JNI Call C To Java.");;
}


/**
* Table of methods associated with a single class.
*/
static JNINativeMethod gMethods[] = {
        { "javaToC", "()Ljava/lang/String;", (void*)jni_call_java_to_c },
        { "CtoJava", "()Ljava/lang/String;", (void*)jni_call_c_to_java },
};

/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
                                 JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}


/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
                               sizeof(gMethods) / sizeof(gMethods[0])))
        return JNI_FALSE;

    return JNI_TRUE;
}

/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!registerNatives(env)) {//注册
        return -1;
    }
    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

    return result;
}

#ifdef __cplusplus
}
#endif
